/*************************************************************************
 * Filename:    IPCManager.h
 * Description: 
 * Group 2:     nachOS
 * Authors:     Ying Wang
 *              Daniel Fairweather
 * Class:       CSE 325
 * Instructor:  Mr. Duggan
 * Assignment:  Lab #4 Interprocess Communication
 * Assigned:    March 5, 2013
 * Due:         March 19, 2013
 *************************************************************************/

#ifndef IPCManager_h
#define IPCManager_h
#ifndef NULL
#define NULL 0
#endif
#define NUM_MAILBOXES 10
#define FREE_SPACE 1000



/**
 * A message block.
 */
typedef struct message_s{
    char message[100];	        /* The message to be sent. */
	int source;	                /* The source (return address). */
	int destination;	        /* The destination to which the message will be sent. */
	struct message_s* next;		/* The next message in a queue. */
	struct message_s* previous; /* The previous message in a queue. */
} message;



/**
 * A queue of message blocks.
 */
typedef struct mailbox_s{
    struct message_s* head;		      /* The first message in the queue. */
	struct message_s* tail;	          /* The last message in the queue. */
	struct message_s last_message;	  /* The last message that was received. */
} mailbox;



/**
 * A freelist.
 */
typedef struct freelist_s{
    int length;                          /* The length of the freelist. */
    struct message_s list[FREE_SPACE];     /* The storage array of the freelist. */
    struct message_s* head;                /* The pointer to the oldest process_control_block in the freelist. */
    struct message_s* tail;                /* The pointer to the newest process_control_block in the freelist. */
} freelist;



mailbox mailboxes[NUM_MAILBOXES];        /* The mailboxes which hold the messages for each manager */
extern int initializedMailboxes[10];         /* The mailboxes which are initialized. */



/**
 * Initializes the required amount of mailboxes.
 * NOTE: Does not free any of the messages!
 * @author Ying Wang
 */
void initalizeMailboxes(int mailboxesToInit[10]);



/**
 * Enqueues a message.
 * @author Ying Wang
 * @param mid The id of the mailbox to preform the operation on.
 * @param The message to enqueue.
 * @returns message* The message that was enqueued.
 */
message* enqueue(int mid, message* message);



/**
 * Dequeues a message.
 * @author Ying Wang
 * @param mid The id of the mailbox to preform the operation on.
 * @returns message* The message that was dequeued.
 */
message* dequeue(int mid);



/**
 * Determines if a mailbox is empty.
 * @author Ying Wang
 * @param mid The id of the mailbox to check.
 * @returns int 0 if the mailbox is not empty, 
 1 if the mailbox is empty,
 -1 if the mailbox id is invalid.
 */
int isEmptyMailbox(int mid);



/**
 * Sends a message from the source manager to the destination manager's mailbox.
 * @author Ying Wang
 * @param sid The id of the source manager.
 * @param did The id of the destination manager's mailbox.
 * @param new_message* The message block to be sent. 
 * @returns int 0 if the message is sent, 
            -1 if source/destination mailboxes don't exist, 
            -2 if all message blocks are used.
 */
int sendMessage(int sid, int did, char* new_message);



/**
 * Retrives the oldest message from the destination manager's mailbox.
 * @author Ying Wang
 * @param did The id of the destination manager's mailbox.
 * @returns int 0 if the message is retrieved and archieved as the last_message,
            -1 if the destination mailboxes don't exist, 
            -2 if the destination mailbox is empty.
 */
int retrieveMessage(int did);



/**
 * Creates a new message block.
 * @author Ying Wang
 * @param sid The source manager's id.
 * @param psw The destination manager's id.
 * @param new_message* The pointer to the content of the new message.
 * @returns message* The message block that was created.
 */
message* createMessage(int sid, int did, char* new_message);



/**
 * Gets a message block from the freelist.
 * @author Ying Wang
 * @returns message* the message block that can be used.
 */
message* getMessageBlock();



/**
 * Appends the message block to the tail of the freelist.
 * @author Ying Wang
 * @param The message to be freed.
 * @returns void.
 */
void freeMessageBlock(message* target);



/**
 * Copies the content of one char array to another.
 * @author Daniel Fairweather
 * @param string1 The pointer to the char array to be copied.
 * @param string2 The pointer to the char array of which we want to change value.
 * @returns int 0 if the message is of the correct length (<=100),
 -1 if the message is too long.
 */
int Stringcopy(char* string1, char* string2);

#endif